
import subprocess
import re
import sys
import os

class SoundManager:
    def __init__(self):
        if os.name != "posix":
            print("请先链接行空板")
            sys.exit(1)
        self.preferred_devices = [
            "usb-Generic_USB2.0",
            "usb-C-Media_INC",
            "usb-Jieli"
        ]
        self.default_input = "alsa_input.platform-acodec-sound.stereo-fallback"
        self.default_output = "alsa_output.platform-acodec-sound.stereo-fallback"
        self.current_output_device = None  # 新增属性，用于记录当前输出设备
        

    def get_device_list(self):
        try:
            result = subprocess.run(["pactl", "list", "sources", "short"], stdout=subprocess.PIPE, text=True, check=True)
            devices = result.stdout.strip().split('\n')
            for device in devices:
                print(device)
        except subprocess.CalledProcessError as e:
            print("Failed to get device list:", e)

    def find_preferred_device_name(self):
        try:
            # 获取所有输出设备的信息
            result = subprocess.run(["pactl", "list", "sinks", "short"], stdout=subprocess.PIPE, text=True, check=True)
            devices = result.stdout.strip().split('\n')  # 按行分割

            preferred_device = None
            external_devices = []
    
            for device in devices:
                # print(device)
                device_info = device.split('\t')  # 按制表符分割
  
                if len(device_info) >1 :
                    device_name = device_info[1]
                    # 检查设备是否在预设的偏好设备列表中
                    if any(preferred_name in device_name for preferred_name in self.preferred_devices):
                        preferred_device = device_name
                        break  # 找到首选设备后跳出循环
                    # 如果设备不是监视器源，将其添加到外接设备列表中
                    external_devices.append(device_name)
                     
          
            # 如果找到首选设备，则返回首选设备
            if preferred_device:
                # print("Preferred device found:123444", preferred_device)
                if preferred_device.endswith('.monitor'):
                    return preferred_device[:-8]
                else:
                    return preferred_device
            # 如果没有首选设备且存在外接设备，则返回第一个外接设备
            elif external_devices:
                if len(external_devices) >1:
                    # print("No preferred device found. Using external device:123", external_devices[1])
                    if external_devices[1].endswith('.monitor'):
                        return external_devices[1][:-8]
                    else:
                        return external_devices[1]
            
            # 如果没有首选设备也没有外接设备，则返回默认设备
            return self.default_output

        except subprocess.CalledProcessError as e:
            print("Failed to find preferred device name:", e)
            return None

    def set_default_output_device_by_name(self, output_device_name):
        # 如果设备名称以 ".monitor" 结尾，则移除它
        if output_device_name.endswith('.monitor'):
            output_device_name = output_device_name[:-8]
        device_name = output_device_name
        try:
            subprocess.run(["pactl", "set-default-sink", device_name], check=True)
    
            self.current_output_device = device_name  # 设置当前输出设备
            print(f"Default output device set to {device_name}")

        except subprocess.CalledProcessError as e:
            print(f"Failed to set default output device to {device_name}:", e)

    def set_default_input_device_by_name(self, input_device_name):
        # 直接使用传递的设备名称
        device_name = input_device_name
        try:
            subprocess.run(["pactl", "set-default-source", device_name], check=True)
            # print(f"Default input device set to {device_name}")
        except subprocess.CalledProcessError as e:
            print(f"Failed to set default input device to {device_name}:", e)

    def set_all_sinks_volume(self, device_name,volume_percent):
            try:
 
                # 设置默认输出设备
                subprocess.run(
                    ["pactl", "set-default-sink", str(device_name)],
                    check=True
                )
                # 设置音量
                subprocess.run(
                    ["pactl", "set-sink-volume", str(device_name), f"{volume_percent}%"],
                    check=True
                )
                print(f"Volume set to {volume_percent}% for device {device_name}")  # 添加打印语句
            except subprocess.CalledProcessError as e:
                # 如果命令执行失败，这里会捕获到异常
                print(f"设置音量失败: {e}")

    def set_all_sources_volume(self, volume_percent):
        # 获取所有输入设备的ID和名称
        source_ids = subprocess.run(["pactl", "list", "short", "sources"], stdout=subprocess.PIPE, text=True).stdout.splitlines()
        for source in source_ids:
            source_info = source.split('\t')
            source_id = source_info[0]
            source_name = source_info[1]
            
            # 检查设备名称是否包含特定字符串
            if "alsa_input.usb-Jieli_Technology_CD002-AUDIO" in source_name:
                # 使用默认的输入设备名称
                source_name_to_set = self.default_input
            else:
                # 排除掉以.monitor结尾的设备
                if ".monitor" not in source_name:
                    source_name_to_set = source_name
                    # print("Setting volume for device:", source_name_to_set)
                else:
                    continue  # 把.monitor设备跳过，不设置音量
            # print(f"Setting volume for device: {source_name_to_set}")
            # 设置每个输入设备的音量
            subprocess.run(["pactl", "set-source-volume", source_name_to_set, f"{volume_percent}%"], check=True)
    def set_volume(self, volume_value):
        if not self.current_output_device:
            preferred_device_full_name = self.find_preferred_device_name()
            self.current_output_device = preferred_device_full_name
        
        volume_value = max(0, min(100, volume_value))  # Clamp the value between 0 and 100
        try:
            self.set_all_sources_volume(100)
            self.set_all_sinks_volume(self.current_output_device,volume_value)
            
            #  print("Volume set to {}%".format(volume_value))
        except subprocess.CalledProcessError as e:
            print("Failed to set volume:", e)
        

    def get_volume(self):
        if not self.current_output_device:
            preferred_device_full_name = self.find_preferred_device_name()
            self.current_output_device = preferred_device_full_name
        else:
            if self.current_output_device.endswith('.monitor'):
                self.current_output_device = self.current_output_device[:-8]
            else:
                self.current_output_device = self.current_output_device
        try:
            # 使用 'pactl list sinks' 命令来获取所有输出设备的信息
            result = subprocess.run(["pactl", "list", "sinks"], stdout=subprocess.PIPE, text=True, check=True)
            # 通过正则表达式找到当前设备的音量信息
             
            pattern = re.compile(r'#\d+.*?' + re.escape(self.current_output_device) + r'.*?front-left:.*?(\d+)%', re.DOTALL)
            match = pattern.search(result.stdout)
            if match:
                volume = match.group(1)
                # print("Current volume is {}%".format(volume))
                return int(volume)
            else:
                # print("Failed to get volume: No matches found for device {}".format(self.current_output_device))
                return None
        except subprocess.CalledProcessError as e:
            print("Failed to get volume:", e)
            return None